#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <time.h>
#include <netdb.h> 
#define SIZE_RECIEVE 500
#define SIZE_SEND 1000

double  res_com_time, res_sort_time, res_total_time;
struct timeval com_time_antes,com_time_depois, sort_time_antes, sort_time_depois, total_time_antes, total_time_depois; //tempos de comunicaçao entre os clientes e servidores, tempo de ordenação e tempo total, respectivamente

pthread_t tid[2];
int vet1[SIZE_RECIEVE], vet2[SIZE_RECIEVE];


void error(const char *msg)
{
    perror(msg);
    exit(1);
}

void ordena(int* ret)
{
	int i=0,j=0,k=0;
	
	while (j<SIZE_RECIEVE && i<SIZE_RECIEVE)
	{
		if (vet1[i]<=vet2[j])
			{
				ret[k] = vet1[i];
				k++;
				i++;
			}
		else 
			{
				ret[k] = vet2[j];
				k++;
				j++;
			}
		
	}
	if (i< SIZE_RECIEVE)
		while (i<SIZE_RECIEVE) 
		{
			ret[k] = vet1[i];
			k++;
			i++;
		}
	if (j< SIZE_RECIEVE)
		while (j<SIZE_RECIEVE) 
		{
			ret[k] = vet2[j];
			k++;
			j++;
		}
}

void* server_receve1()
{     int sockfd, newsockfd,portno;
     socklen_t clilen;
     char buffer[256];
	int i=0;
     struct sockaddr_in serv_addr, cli_addr;
     int n;


     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0) 
        error("ERROR opening socket");
     bzero((char *) &serv_addr, sizeof(serv_addr));
	portno = 1234;
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(portno);

     if (bind(sockfd, (struct sockaddr *) &serv_addr,
              sizeof(serv_addr)) < 0) 
              error("ERROR on binding");
     listen(sockfd,1);
     clilen = sizeof(cli_addr);
     newsockfd = accept(sockfd, 
                 (struct sockaddr *) &cli_addr, 
                 &clilen);
     if (newsockfd < 0) 
          error("ERROR on accept");
	i=0;
    
	bzero(buffer,256);     
	while(i<SIZE_RECIEVE){ 
     
     n = read(newsockfd,buffer,255);
     if (n < 0) error("ERROR reading from socket");

	vet2[i]=atoi(buffer);
	printf("%d:   %d \n",i,vet2[i]);
	i++;
	}
	close(newsockfd);
   	close(sockfd);
	pthread_exit(NULL);

	
	}

void* server_receve()
{
     int sockfd, newsockfd,portno;
     socklen_t clilen;
     char buffer[256];
	int i=0;
     struct sockaddr_in serv_addr, cli_addr;
     int n;
	pthread_create(&(tid[1]), NULL, &server_receve1, NULL);

     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0) 
        error("ERROR opening socket");
     bzero((char *) &serv_addr, sizeof(serv_addr));
	portno = 1235;
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(portno);

     if (bind(sockfd, (struct sockaddr *) &serv_addr,
              sizeof(serv_addr)) < 0) 
              error("ERROR on binding");
     listen(sockfd,1);
     gettimeofday(&com_time_antes,NULL);
     clilen = sizeof(cli_addr);
     newsockfd = accept(sockfd, 
                 (struct sockaddr *) &cli_addr, 
                 &clilen);
     if (newsockfd < 0) 
          error("ERROR on accept");
	i=0;
    
	bzero(buffer,256);     
	while(i<SIZE_RECIEVE){ 
        n = read(newsockfd,buffer,255);
     if (n < 0) error("ERROR reading from socket");

	vet1[i]=atoi(buffer);
	printf("%d:   %d \n",i,vet1[i]);
     i++;
}
close(newsockfd);
    close(sockfd);

	pthread_join(tid[1],NULL);
	pthread_exit(NULL);
	
}

int main(int argc, char *argv[])
{
	gettimeofday(&total_time_antes, NULL); 	
	int i=0, vet[SIZE_SEND];
	

	pthread_create(&(tid[0]), NULL, &server_receve, NULL);
	pthread_join(tid[0],NULL);
        gettimeofday(&com_time_depois,NULL);
	gettimeofday(&sort_time_antes, NULL); 
	ordena(vet);	
	gettimeofday(&sort_time_depois, NULL); 	
	printf ("\nVETOR FINAL ORDENADO:\n");
	
		

        while (i< SIZE_SEND) 
	{
		printf ("%d: %d \n", i, vet[i]);
		i++;
	}

	gettimeofday(&total_time_depois, NULL); 

	//RESULTADOS: Diferença entre os tempos medidos dará o tempo de execução 	
	 //Tempo de ordenaçao
	 res_sort_time = ((double)(sort_time_depois.tv_sec - sort_time_antes.tv_sec)) + (((double)(sort_time_depois.tv_usec - sort_time_antes.tv_usec))/1000000);
	 //Tempo de comunicaçao cliente e servidor
	 res_com_time = ((double)(com_time_depois.tv_sec - com_time_antes.tv_sec)) + (((double)(com_time_depois.tv_usec - com_time_antes.tv_usec))/1000000);
	//Tempo total
	 res_total_time = ((double)(total_time_depois.tv_sec - total_time_antes.tv_sec)) + (((double)(total_time_depois.tv_usec - total_time_antes.tv_usec))/1000000);	
	    
	printf("\nTEMPOS: \n Comunication time: %0.6lf\n Sort time: %0.6lf\n Total time: %0.6lf\n", res_com_time, res_sort_time, res_total_time); 	
        
	
	return 0; 
}
